"""
CSPBuilder plugin

Provides the configuration functionality for python code files

Copyright (c) 2008 Rune M. Friborg, runef@diku.dk.
See LICENSE.txt for licensing details (GPLv2).
"""

PLUGIN_NAME = "Setup"

try:
    import cPickle as pickle
except:
    import pickle

import base64
import os
import wx

from extensions import cspxml
from plugins.builder import *


class PluginSetup(PluginBUILDER):

    def __init__(self, pluginManager):
        PluginBUILDER.__init__(self, pluginManager, PLUGIN_NAME)

        self.pluginman = pluginManager

    def findConfigurableProcesses(self, returnList, process, l=0, path='', replace=None):

        # Get prog name
        if (l==1):
            process_att = cspxml.getAttrList(process)
            if replace:
                process_att['name']= replace[1]
            process_name = process_att['name']
        elif (l>1):
            process_att = cspxml.getAttrList(process)
            if replace:
                process_att['name']= replace[1]
            process_name = path + '.' + process_att['name']           
        else:
            process_name = ''
        
        for elem in process.childNodes:
            if (elem.nodeName == 'processlink'):
                att = cspxml.getAttrList(elem)

                # Find location and parse file.
                plist_document = None
                for path in self.pluginman.getList(pathlist_COMPONENTS) + [sys.path[0] + '/Components'] + [sys.path[0]]:
                    pathAndFilename = path + '/' + att['file']
                    if os.path.exists(pathAndFilename):
                        # Parse
                        plist_document = cspxml.parseFile(pathAndFilename)
                        break
                if not plist_document:
                    print 'Could not locate file ' + att['file']
                    sys.exit(1)
                
                for plist_e1 in plist_document.childNodes:
                    if (plist_e1.nodeName == "doc"):
                        for plist_e2 in plist_e1.childNodes:
                            if (plist_e2.nodeName == "process"):
                                att2 = cspxml.getAttrList(plist_e2)
                                if (att2['name'] == att['process']):
                                    # Interpret process
                                    if (att['process'] != att['name']):
                                        # Replace component processname, with the one given in processlink
                                        self.findConfigurableProcesses(returnList, plist_e2, l+1, process_name, (att['process'],att['name']))
                                    else:
                                        self.findConfigurableProcesses(returnList, plist_e2, l+1, process_name)

            elif (elem.nodeName == 'process'):
                self.findConfigurableProcesses(returnList, elem, l+1, process_name)

        for elem in process.childNodes:
            if (elem.nodeName == 'code'):
                att = cspxml.getAttrList(elem)
                if (att.has_key('configurable') and att['configurable'] == 'yes'):
                    #returnList[process_name] = att['src']
                    returnList[process_name] = process_name + '___csp'


    def _rcmenuClear(self, frame, menu, obj, menuid):
        menu.Append(menuid, 'Clear Configuration')
        frame.Bind(wx.EVT_MENU, lambda event:self._rcmenuClear_activate(frame,event), id=menuid)

    def _rcmenuClear_activate(self, frame, event):

        obj = frame.selection[0]
        
        # Find all process implementations and list them in a dialog box.
        codeLookup = {}
        if obj.cspData.has_key('componentFile'):

            document = cspxml.parseFile(obj.cspData['componentFile'])

            for e1 in document.childNodes:
                if (e1.nodeName == "doc"):
                    for e2 in e1.childNodes:
                        if (e2.nodeName == "process"):
                            att = cspxml.getAttrList(e2)
                            if (att['name'] == obj.cspData['process']):
                                self.findConfigurableProcesses(codeLookup, e2)

        selectList = codeLookup.keys()
        selectList.sort()

        dlg = wx.SingleChoiceDialog(
            frame, 'Select Function To Clear', 'Available Configurable Functions', selectList, wx.CHOICEDLG_STYLE
            )
        
        if dlg.ShowModal() == wx.ID_OK and dlg.GetStringSelection() != "":
            selected = dlg.GetStringSelection()

            #Clear
            if (obj.plugin_tags.has_key('configData')):
                if (obj.plugin_tags['configData'].has_key(selected)):
                    del obj.plugin_tags['configData'][selected]


    def _rcmenuSetup(self, frame, menu, obj, menuid):
        menu.Append(menuid, 'Configure')
        frame.Bind(wx.EVT_MENU, lambda event:self._rcmenuSetup_activate(frame,event), id=menuid)


    def _rcmenuSetup_activate(self, frame, event):

        obj = frame.selection[0]
        
        # Find all process implementations and list them in a dialog box.
        codeLookup = {}
        if obj.cspData.has_key('componentFile'):

            # select right version
            objVer = obj.getVersion()
            versions = obj.getAvailVersions()
            if objVer == 'newest':
                if len(versions['serverVersions']):
                    ver = max(versions['serverVersions'])
                    versionDir = 'version%06d' % ver
                else:
                    ver = max(versions['editVersions'])
                    versionDir = 'e_version%06d' % ver
            elif objVer.startswith('e'):
                ver = max(versions['editVersions'])
                versionDir = 'e_version%06d' % ver
            else:
                ver = max(versions['serverVersions'])
                versionDir = 'version%06d' % ver
            
            filePath = os.path.join(obj.cspData['componentFile'],versionDir,'main.csp')
            #document = cspxml.parseFile(obj.cspData['componentFile'])
            document = cspxml.parseFile(filePath)

            for e1 in document.childNodes:
                if (e1.nodeName == "doc"):
                    for e2 in e1.childNodes:
                        if (e2.nodeName == "process"):
                            att = cspxml.getAttrList(e2)
                            if (att['name'] == obj.cspData['process']):
                                self.findConfigurableProcesses(codeLookup, e2)

        selectList = codeLookup.keys()
        selectList.sort()

        dlg = wx.SingleChoiceDialog(
            frame, 'Select Function', 'Available Configurable Functions', selectList, wx.CHOICEDLG_STYLE
            )
        
        if dlg.ShowModal() == wx.ID_OK and dlg.GetStringSelection() != "":
            selected = dlg.GetStringSelection()
            # Find file
            #pyFile = codeLookup[selected]
            pyModule = codeLookup[selected]
            #if (codeLookup[selected]+'.py' in os.listdir(self.workingDir + '/Components')):
            #    pyFile= 'Components/' + codeLookup[selected]

            try:
                print 'Importing module:', pyModule
                #x = __import__(pyFile)
                x = __import__(pyModule)
            except:
                #print 'Error: Code could not be found:', pyFile
                print 'Error: Module could not be found:', pyModule
                return None

            # Call setup function and save serialized return data.

            configData = None
            if (obj.plugin_tags.has_key('configData')):
                print '1'
                if (obj.plugin_tags['configData'].has_key(selected)):
                    configData = pickle.dumps(x.setup(pickle.loads(obj.plugin_tags['configData'][selected])))
                else:
                    configData = pickle.dumps(x.setup())
                obj.plugin_tags['configData'][selected] = configData
            else:
                print '2'
                configData = pickle.dumps(x.setup())
                obj.plugin_tags['configData'] = {selected:configData}


    def createTag(self, node, obj_plugin_tags):
        # Save config
        if (obj_plugin_tags.has_key('configData')):
            for configuredProcess in obj_plugin_tags['configData']:
                configNode = cspxml.createDom().createElement('config')
                configNode.setAttribute('data', base64.b64encode(obj_plugin_tags['configData'][configuredProcess]))
                configNode.setAttribute('process', configuredProcess)
                node.appendChild(configNode)
        return node



    def loadTag(self, node, obj_plugin_tags):

        # Get config data if any exists
        for config in node.childNodes:
            if (config.nodeName == 'config'):
                configNode = config

                att = cspxml.getAttrList(configNode)
                if (obj_plugin_tags.has_key('configData')):
                    obj_plugin_tags['configData'][att['process']] = base64.b64decode(att['data'])
                else:
                    obj_plugin_tags['configData'] = {att['process']:base64.b64decode(att['data'])}
        
        return obj_plugin_tags


def load(pluginManager):

    p = PluginSetup(pluginManager)

    p.addCSPTag(node_PROCESS_LINK, p.createTag, p.loadTag)
    p.addRightClickElement(location_PROCESS_LINK, p._rcmenuSetup)
    p.addRightClickElement(location_PROCESS_LINK, p._rcmenuClear)
    
    pluginManager.addPlugin(p)
